package org.budo.warehouse.logic.consumer.jdbc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;

import org.budo.graph.annotation.SpringGraph;
import org.budo.support.java.concurrent.executor.ExecutorUtil;
import org.budo.warehouse.logic.api.DataMessage;
import org.budo.warehouse.logic.bean.LogicDynamicBeanProvider;
import org.budo.warehouse.service.api.JdbcExecuteService;
import org.budo.warehouse.service.entity.DataNode;
import org.springframework.aop.framework.AopContext;

import lombok.Getter;
import lombok.Setter;

/**
 * @author limingwei
 */
@Getter
@Setter
public class JdbcDataConsumer extends AbstractJdbcDataConsumer {
    @Resource
    private LogicDynamicBeanProvider logicDynamicBeanProvider;

    @Resource
    private JdbcExecuteService jdbcExecuteService;

    /**
     * 为空时主线程执行
     */
    private ExecutorService executorService;

    @SpringGraph
    @Override
    public void consume(DataMessage dataMessage) {
        List<SqlUnit> sqlUnits = this.buildSql(dataMessage);
        if (null == sqlUnits || sqlUnits.isEmpty()) { // 空的
            return;
        }

        JdbcDataConsumer _this = (JdbcDataConsumer) AopContext.currentProxy();

        // 按批次大小分方法，便于性能统计优化
        int len = sqlUnits.size();
        if (len < 2) { // 单条
            _this.execute_1(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 3) {
            _this.execute_2(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 4) {
            _this.execute_3(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 5) {
            _this.execute_4(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 6) {
            _this.execute_5(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 11) {
            _this.execute_6_10(this.getDataNode(), sqlUnits);
            return;
        }

        if (len < 20) {
            _this.execute_11_20(this.getDataNode(), sqlUnits);
            return;
        }

        _this.execute_21_(this.getDataNode(), sqlUnits);
        return;
    }

    @SpringGraph
    public void execute_1(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_2(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_3(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_4(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_5(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_6_10(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_11_20(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    @SpringGraph
    public void execute_21_(DataNode dataNode, List<SqlUnit> sqlUnits) {
        this.execute_in_thread(dataNode, sqlUnits);
    }

    private void execute_in_thread(final DataNode dataNode, final List<SqlUnit> sqlUnits) {
        List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();

        for (final SqlUnit sqlUnit : sqlUnits) {
            Runnable runnable = new Runnable() {
                public void run() {
                    jdbcExecuteService.executeUpdate(dataNode.getId(), sqlUnit.getSql(), sqlUnit.getParameters());
                }
            };

            tasks.add(Executors.callable(runnable));
        }

        // 全部执行完后返回
        ExecutorUtil.invokeAll(this.getExecutorService(), tasks);
    }
}